<?php
class DB
{

    private static $dsn;
    private static $tmp_dsn;

    protected   $db_link;
    protected   $hash_str;
    protected   $last_error;
    protected   $logs;

    public      $affected_rows  = 0;
    public      $page;

    function &__construct($const_db = null, $hash = null)
    {
        if ($const_db)
        {
            $this->load_dsn($const_db, $hash);
        }
        return $this;
    }

    function __destruct()
    {
        is_resource($this->db_link) && mysql_close($this->db_link);
    }
//$const_db表示的是数据库选项
    function load_dsn($const_db, $hash = null, $need_hash = true)
    {
        DB_DEBUG && $this->logs[] = "[T] loadDsn({$const_db}, {$hash})";
        $this->hash_str = $hash;
        if ($const_db)
        {
            if (!(self::$tmp_dsn = get_data_source($const_db, $hash, $need_hash)))
            {
                self::$dsn = self::$tmp_dsn;
                return;
            }

            if (self::$dsn['host'] == self::$tmp_dsn['host'])
            {
                if (self::$dsn['database'] != self::$tmp_dsn['database'] && is_resource($this->db_link))
                {
                    $this->logs[] = "[T] USE ".self::$tmp_dsn['database'];
                    if (!mysql_select_db(self::$tmp_dsn['database'], $this->db_link) && DB_DEBUG)
                    {
                        $this->logs[] = "[E] ".mysql_error($this->db_link);
                    }
                }
                self::$dsn = self::$tmp_dsn;
                return;
            }
            else
            {
                self::$dsn = self::$tmp_dsn;
                $this->close();
            }
        }
        if($const_db == "bill")
        {
            self::$dsn['database'] = "dmz_bill_20141231";
        }



    }

    function set_error($msg)
    {
        $this->last_error = $msg;
        if (DB_DEBUG && !empty($msg))
        {
            $this->logs[] = $msg;
        }
    }

    function &last_error()
    {
        return $this->last_error;
    }

    function connect()
    {
        if (is_resource($this->db_link))
        {
            return; 
        }

        $feedback = 'Server busy, please try again later.';

        if (empty(self::$dsn))
        {
            $this->set_error('Lost data source');
            echo $feedback;
            $this->dump();
            exit;
        }
        DB_DEBUG && $temp_start   = microtime(1);
        $this->db_link = mysql_connect(self::$dsn['host'], self::$dsn['user'], self::$dsn['pass']);
        if (!$this->db_link)
        {
            echo $feedback;
            $this->dump();
            exit;
        }
        DB_DEBUG && $this->logs[] = "[T] connect time:".(microtime(1) - $temp_start);

        if (isset(self::$dsn['database']))
        {
            if (!mysql_select_db(self::$dsn['database']) && DB_DEBUG)
            {
                $this->logs[] = "[E] ".mysql_error($this->db_link);
            }
            else
            {
                mysql_query('SET NAMES utf8');
            }
        }
    }

    protected function &_query($sql, $query_with_page = false)
    {
        is_resource($this->db_link) || $this->connect();

        $result                 = false;
        $this->last_error       = null;
        $this->affected_rows    = 0;

        if (!empty(self::$dsn['table_alias']))
        {
            if (DB_DEBUG)
            {
                //$this->logs[] = "[O] {$sql}";
               // $sql = preg_replace('/([from|update]\s+)'.self::$dsn['table_alias'].' ?/i', '\1'.self::$dsn['table'].' ', $sql, 1);
				$sql = preg_replace(
                        '/(from|update|insert|insert into|replace into|delete|delete from)\s+'.self::$dsn['table_alias'].' ?/is',
                        ' \1 '.self::$dsn['table'].' ',
                        $sql,
                        1
                   );
            }
            else
            {
                //$sql = preg_replace('/([from|update]\s+)'.self::$dsn['table_alias'].' ?/i', '\1'.self::$dsn['table'].' ', $sql, 1);
				$sql = preg_replace(
                        '/(from|update|insert|insert into|replace into|delete|delete from)\s+'.self::$dsn['table_alias'].' ?/is',
                        ' \1 '.self::$dsn['table'].' ',
                        $sql,
                        1
                   );
            }
        }

        if ($query_with_page)
        {
            if (1 > $this->page['total_rows'])
            {

                if (false == ($count_sql = stristr($sql, 'from')))
                {
                    $this->set_error("[E] Parse SQL fail {$sql}");
                    return $result;
                }
                $count_sql = "SELECT COUNT(1) ".$count_sql;
                DB_DEBUG && $start_time = array_sum(explode(' ', microtime()));
                $tmp_result= mysql_query($count_sql, $this->db_link);
                DB_DEBUG && $query_time = array_sum(explode(' ', microtime())) - $start_time;
                if (DB_DEBUG)
                {
                    $this->logs[] = "[Q] {$count_sql}";
                    $this->logs[] = sprintf("[QUERY_WITH_PAGE] consumed %.5f sec", $query_time);
                }

                if (mysql_errno($this->db_link))
                {
                    $this->set_error(mysql_error($this->db_link));
                    return $result;
                }
                $tmp_result= mysql_fetch_row($tmp_result);
                $this->page['total_rows']  = $tmp_result[0];
            }
            $this->page['total_pages'] = ceil($this->page['total_rows'] / $this->page['size']);

            if ($this->page['total_pages'] < $this->page['current'])
            {
                $this->page['current'] = $this->page['total_pages'];
            }
            if (2 > intval($this->page['current']))
            {
                $this->page['current'] = 1;
            }

            $reverse_limit = false;

            if (isset($this->page['reverse_limit']))
            {
                if ($this->page['reverse_limit'] < $this->page['total_rows'])
                {
                    $new_page = false;
                    if ($this->page['current'] == $this->page['total_pages'])
                    {
                        $new_page = 1;
                    }
                    else
                    {
                        $half = floor($this->page['total_pages'] / 2);
                        if ($half < $this->page['current'])
                        {
                            $new_page = $this->page['total_pages'] - ($this->page['current']) + 1;
                        }
                    }
                    if ($new_page)
                    {
                        $sql = str_replace($this->page['reverse_asc'], $this->page['reverse_desc'], $sql);
                        $sql.= ' LIMIT '.(($new_page - 1) * $this->page['size']).','.$this->page['size'];
                        $reverse_limit = true;
                    }
                }
            }

            if (!$reverse_limit)
            {
                $sql .= ' LIMIT '.(($this->page['current'] - 1) * $this->page['size']).','.$this->page['size'];
            }
        }

        if (DB_DEBUG)
        {
            $start_time = array_sum(explode(' ', microtime()));
            $result = mysql_query($sql, $this->db_link);
            $query_time = array_sum(explode(' ', microtime())) - $start_time;

            $this->logs[] = "[Q] {$sql}";

            if (mysql_errno($this->db_link))
            {
                $this->setError(mysql_error($this->db_link));
            }
            else 
            {
                $this->affected_rows = is_resource($result) ? mysql_num_rows($result) : mysql_affected_rows($this->db_link);
                $this->logs[]        = sprintf("[R] %s rows in set (<span style='%s'>%.5f sec</span>)", $this->affected_rows, ($query_time>1?'font-weight:bold;color:red':($query_time>0.5?'color:red':($query_time>0.1?'color:blue':($query_time>0.01?'color:#c96':'color:green')))), $query_time);
            }
        }
        else 
        {
            if (CAPTURE_LONGSQL_TIME > 0) 
            {
                $start_time = array_sum(explode(' ', microtime()));
                $result     = mysql_query($sql, $this->db_link);
                $query_time = array_sum(explode(' ', microtime())) - $start_time;
                if ($query_time > CAPTURE_LONGSQL_TIME) 
                {
                    $this->saveLogOfCaptureLongSql($sql, $query_time);
                }
            } 
            else 
            {
                $result = mysql_query($sql, $this->db_link);
            }
            $error_no = mysql_errno($this->db_link);
            if ($error_no) 
            {
                $this->set_error(mysql_error($this->db_link));
                if (DB_ERROR_LOG && (1062 != $error_no)) 
                { // ignore error [Duplicate entry 'xxx' for key 1]
                    error_log(sprintf("[Q] %s \n[E] %s(Hash=%s)\n", $sql, $this->last_error, $this->hash_str), 3, DB_ERROR_LOG_FILE);
                }
            } 
            else 
            {
                $this->affected_rows = is_resource($result) ? mysql_num_rows($result) : mysql_affected_rows($this->db_link);
            }
        } 
        return $result;
    }

    function insert_id() 
    {
        return mysql_insert_id($this->db_link);
    }

    function &query($sql, $const_ret_type = DB_RET_RES) 
    {

        $ret = false;
        $res = $this->_query($sql);

        if ($this->affected_rows) 
        {
            switch ($const_ret_type) 
            {
                case DB_RET_ROW:
                    $ret = mysql_fetch_assoc($res);
                    mysql_free_result($res);
                    break;

                case DB_RET_ROWS:
                    $ret = array();
                    while($row = mysql_fetch_assoc($res)) 
                    {
                        $ret[] = $row;

                    }
                    mysql_free_result($res);
                    break;

                case DB_RET_VALUE:
                    $ret = mysql_fetch_row($res);
                    $ret = $ret[0];
                    mysql_free_result($res);
                    break;

                case DB_RET_RES:
                default:
                    $ret = &$res;
            }
        }
        return $ret;
    }

    function &get_row($sql) 
    {
        return $this->query($sql, DB_RET_ROW);
    }

    function &get_rows($sql) 
    {
        return $this->query($sql, DB_RET_ROWS);
    }

    function &get_value($sql) 
    {
        return $this->query($sql, DB_RET_VALUE);
    }

    function get_page() 
    {
        return $this->page;
    }

    /* ---------------------------------------------------
     * $limit : 达到多少条记录后开始反转翻页
     * $asc   : 不颠倒翻页时的排序方式
     * $desc  : 颠倒翻页时的排序方式
     * -------------------------------------------
     */
    function reverse_order($limit, $asc, $desc) 
    {
        $this->page['reverse_limit']    = intval($limit);
        $this->page['reverse_asc']      = $asc;
        $this->page['reverse_desc']     = $desc;
    }

    function &query_with_page($sql, $current_page = 1, $total_rows = 0, $page_size = DB_DEFAULT_PAGE_SIZE) 
    {
        $this->page['size']         = (int)$page_size;
        $this->page['current']      = (int)$current_page;
        $this->page['total_rows']   = (int)$total_rows;
        $this->page['total_pages']  = 1;

        $ret = false;
        $res = $this->_query($sql, true);

        if ($this->affected_rows) 
        {
            $ret = array();
            while($row = mysql_fetch_assoc($res)) 
            {
                $ret["rows"][] = $row;
            }
            mysql_free_result($res);
            $ret["page"] = $this->get_page();
        }

        return $ret;
    }

    function close() 
    {
        is_resource($this->db_link) && mysql_close($this->db_link);
    }

    function dump() 
    {
        if (DB_DEBUG) 
        {
            print_r(self::$dsn);
            print_r($this);
        }
    }

    private function save_log_of_capture_long_sql($sql, $query_time) 
    {
        error_log(date("Ymd H:i:s") . ",$query_time,$sql\n", 3, CAPTURE_LONGSQL_LOG_FILE . substr(md5(uniqid()), 0, 1));
        //error_log(date("Ymd H:i:s") . ",$query_time,$sql\n", 3, CAPTURE_LONGSQL_LOG_FILE . 'a');
    }

	 /**
     * 将数组转换成字符串
     * @return mix 成功则返回string，否则false
     * @param array $param 需要转换的数组
     * @param string $type 指定类别，更新记录为update，插入数据为insert
     */
    function array_to_string($param, $type = 'insert')
    {
        if (empty($param) || !is_array($param))
        {
            return false;
        }
        if (is_array($param) && $type == 'insert')
        {
            $fields = '';
            $values = '';
            foreach ($param as $key=>$value)
            {
                $fields .= $key.',';
                $values .= "'".$value."',";
            }
            $string = "(".substr($fields, 0, -1).") values (".substr($values, 0, -1).")";
            return $string;
        }
        elseif (is_array($param) && $type == 'update')
        {
            $string = '';
            foreach ($param as $key=>$value)
            {
                ###如果在前面加=，则表示自增
                if (substr($value, 0, 2) == '=-')
                {
                    $string .= $key ."=".$key."-".substr($value, 2).",";
                }
                elseif (substr($value, 0, 1) == '=')
                {
                    $string .= $key ."=".$key."+".substr($value, 1).",";
                }
                else 
                {
                    $string .= $key ."='".$value."',";
                }
            }
            $string = substr($string, 0, -1);
            return $string;           
        }
        return false;
    }
    
	/*变量过滤，单个变量或一维数组*/
    function escape_parameter($param){
    	if(get_magic_quotes_gpc()){
    		if(is_array($param)){
    			foreach($param as $key=>$value){
					$param[$key] = mysql_escape_string(stripslashes($value));
    			}
    			return $param;
    		}else{
				return mysql_escape_string(stripslashes($param));
    		}
    	}else{
    		if(is_array($param)){
    			foreach($param as $key=>$value){
					$param[$key] = mysql_escape_string($value);
    			}
    			return $param;
    		}else{
				return mysql_escape_string($param);
    		}
    	}
    }

} // end class DB
?>
